﻿using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using ESRI.ArcGIS.Client.Tasks;

namespace ESRI.ArcGIS.Client.Async
{
    public static partial class GeoprocessorExtensions
    {
        #region CheckJobStatus

        /// <summary>
        /// Sends a request to the geoprocessing task for the current state of the job identified by jobId.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="jobId">A string that uniquely identifies a job on the server. It is created when
        /// a job is submitted for execution and later used to check its status and retrieve the results.</param>
        /// <returns></returns>
        public static Task<JobInfoTaskResult> CheckJobStatusTaskAsync(this Geoprocessor task, string jobId)
        {
            return CheckJobStatusTaskAsync(task, jobId, CancellationToken.None);
        }

        /// <summary>
        /// Sends a request to the geoprocessing task for the current state of the job identified by jobId.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="jobId">A string that uniquely identifies a job on the server. It is created when
        /// a job is submitted for execution and later used to check its status and retrieve the results.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<JobInfoTaskResult> CheckJobStatusTaskAsync(this Geoprocessor task, string jobId,
            CancellationToken cancellationToken)
        {
            return task.HandleTask<Geoprocessor, JobInfoEventArgs, JobInfoTaskResult>(
                t => t.CheckJobStatusAsync(jobId),
                (t, e) => t.StatusUpdated += e,
                (t, e) => t.StatusUpdated -= e,
                e => new JobInfoTaskResult(e),
                cancellationToken);
        }

        #endregion

        #region Execute

        /// <summary>
        /// Executes the task.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="parameters">The parameters to use to execute the task.</param>
        /// <returns></returns>
        public static Task<GPExecuteTaskResult> ExecuteTaskAsync(this Geoprocessor task, List<GPParameter> parameters)
        {
            return ExecuteTaskAsync(task, parameters, CancellationToken.None);
        }

        /// <summary>
        /// Executes the task.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="parameters">The parameters to use to execute the task.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<GPExecuteTaskResult> ExecuteTaskAsync(this Geoprocessor task, List<GPParameter> parameters,
            CancellationToken cancellationToken)
        {
            return task.HandleTask<Geoprocessor, GPExecuteCompleteEventArgs, GPExecuteTaskResult>(
                t => t.ExecuteAsync(parameters),
                (t, e) => t.ExecuteCompleted += e,
                (t, e) => t.ExecuteCompleted -= e,
                e => new GPExecuteTaskResult(e),
                cancellationToken);
        }

        #endregion

        #region GetInput

        /// <summary>
        /// Sends a request to the Geoprocessor task to get the task input identified by jobId and parameterName.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="jobId">A string that uniquely identifies a job on the server.
        /// It is created when a job is submitted for execution and later used to check its status and retrieve the results.</param>
        /// <param name="parameterName">The name of the input parameter as defined in ArcGIS Services Directory.</param>
        /// <returns></returns>
        public static Task<GPParameterTaskResult> GetInputTaskAsync(this Geoprocessor task, string jobId, string parameterName)
        {
            return GetInputTaskAsync(task, jobId, parameterName, CancellationToken.None);
        }

        /// <summary>
        /// Sends a request to the Geoprocessor task to get the task input identified by jobId and parameterName.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="jobId">A string that uniquely identifies a job on the server.
        /// It is created when a job is submitted for execution and later used to check its status and retrieve the results.</param>
        /// <param name="parameterName">The name of the input parameter as defined in ArcGIS Services Directory.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<GPParameterTaskResult> GetInputTaskAsync(this Geoprocessor task, string jobId, string parameterName,
            CancellationToken cancellationToken)
        {
            return task.HandleTask<Geoprocessor, GPParameterEventArgs, GPParameterTaskResult>(
                t => t.GetInputAsync(jobId, parameterName),
                (t, e) => t.GetInputCompleted += e,
                (t, e) => t.GetInputCompleted -= e,
                e => new GPParameterTaskResult(e),
                cancellationToken);
        }

        #endregion

        #region GetResultData

        /// <summary>
        /// Sends a request to the Geoprocessor task to get the task result identified by jobId and parameterName.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="jobId">A string that uniquely identifies a job on the server. It is created when
        /// a job is submitted for execution and later used to check its status and retrieve the results.</param>
        /// <param name="parameterName">The name of the result parameter as defined in ArcGIS Services Directory.</param>
        /// <returns></returns>
        public static Task<GPParameterTaskResult> GetResultDataTaskAsync(this Geoprocessor task, string jobId, string parameterName)
        {
            return GetResultDataTaskAsync(task, jobId, parameterName, CancellationToken.None);
        }

        /// <summary>
        /// Sends a request to the Geoprocessor task to get the task result identified by jobId and parameterName.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="jobId">A string that uniquely identifies a job on the server. It is created
        /// when a job is submitted for execution and later used to check its status and retrieve the results.</param>
        /// <param name="parameterName">The name of the result parameter as defined in ArcGIS Services Directory.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<GPParameterTaskResult> GetResultDataTaskAsync(this Geoprocessor task, string jobId, string parameterName,
            CancellationToken cancellationToken)
        {
            return task.HandleTask<Geoprocessor, GPParameterEventArgs, GPParameterTaskResult>(
                t => t.GetResultDataAsync(jobId, parameterName),
                (t, e) => t.GetResultDataCompleted += e,
                (t, e) => t.GetResultDataCompleted -= e,
                e => new GPParameterTaskResult(e),
                cancellationToken);
        }

        #endregion

        #region GetResultImage

        /// <summary>
        /// Sends a request to the Geoprocessor task to get the task result identified by jobId and parameterName.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="jobId">A string that uniquely identifies a job on the server. It is created
        /// when a job is submitted for execution and later used to check its status and retrieve the results.</param>
        /// <param name="parameterName">The name of the result parameter as defined in ArcGIS Services Directory.</param>
        /// <returns></returns>
        public static Task<GetResultImageTaskResult> GetResultImageTaskAsync(this Geoprocessor task, string jobId, string parameterName)
        {
            return GetResultImageTaskAsync(task, jobId, parameterName, CancellationToken.None);
        }

        /// <summary>
        /// Sends a request to the Geoprocessor task to get the task result identified by jobId and parameterName.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="jobId">A string that uniquely identifies a job on the server. It is created
        /// when a job is submitted for execution and later used to check its status and retrieve the results.</param>
        /// <param name="parameterName">The name of the result parameter as defined in ArcGIS Services Directory.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<GetResultImageTaskResult> GetResultImageTaskAsync(this Geoprocessor task, string jobId, string parameterName,
            CancellationToken cancellationToken)
        {
            return task.HandleTask<Geoprocessor, GetResultImageEventArgs, GetResultImageTaskResult>(
                t => t.GetResultImageAsync(jobId, parameterName),
                (t, e) => t.GetResultImageCompleted += e,
                (t, e) => t.GetResultImageCompleted -= e,
                e => new GetResultImageTaskResult(e),
                cancellationToken);
        }

        #endregion

        #region GetResultImageLayer

        /// <summary>
        /// Sends a request to the Geoprocessor task to get the task result identified by jobId and parameterName.
        /// Creates and configures a GPResultImageLayer instance ready to be added to a Map.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="jobId">A string that uniquely identifies a job on the server. It is created
        /// when a job is submitted for execution and later used to check its status and retrieve the results.</param>
        /// <param name="parameterName">The name of the result parameter as defined in ArcGIS Services Directory.</param>
        /// <returns></returns>
        public static Task<GetResultImageLayerTaskResult> GetResultImageLayerTaskAsync(this Geoprocessor task, string jobId, string parameterName)
        {
            return GetResultImageLayerTaskAsync(task, jobId, parameterName, CancellationToken.None);
        }

        /// <summary>
        /// Sends a request to the Geoprocessor task to get the task result identified by jobId and parameterName.
        /// Creates and configures a GPResultImageLayer instance ready to be added to a Map.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="jobId">A string that uniquely identifies a job on the server. It is created
        /// when a job is submitted for execution and later used to check its status and retrieve the results.</param>
        /// <param name="parameterName">The name of the result parameter as defined in ArcGIS Services Directory.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<GetResultImageLayerTaskResult> GetResultImageLayerTaskAsync(this Geoprocessor task, string jobId, string parameterName,
            CancellationToken cancellationToken)
        {
            return task.HandleTask<Geoprocessor, GetResultImageLayerEventArgs, GetResultImageLayerTaskResult>(
                t => t.GetResultImageLayerAsync(jobId, parameterName),
                (t, e) => t.GetResultImageLayerCompleted += e,
                (t, e) => t.GetResultImageLayerCompleted -= e,
                e => new GetResultImageLayerTaskResult(e),
                cancellationToken);
        }

        #endregion

        #region SubmitJob

        /// <summary>
        /// Submits a job request to the server to execute an asynchronous geoprocessing task.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="parameters">The parameters to use to submit a job to the task.</param>
        /// <returns></returns>
        public static Task<JobInfoTaskResult> SubmitJobTaskAsync(this Geoprocessor task, List<GPParameter> parameters)
        {
            return SubmitJobTaskAsync(task, parameters, CancellationToken.None);
        }

        /// <summary>
        /// Submits a job request to the server to execute an asynchronous geoprocessing task.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="parameters">The parameters to use to submit a job to the task.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<JobInfoTaskResult> SubmitJobTaskAsync(this Geoprocessor task, List<GPParameter> parameters,
            CancellationToken cancellationToken)
        {
            return task.HandleTask<Geoprocessor, JobInfoEventArgs, JobInfoTaskResult>(
                t => t.SubmitJobAsync(parameters),
                (t, e) => t.JobCompleted += e,
                (t, e) => t.JobCompleted -= e,
                e => new JobInfoTaskResult(e),
                cancellationToken);
        }

        #endregion

    }
}
